package bg.uni_sofia.conf_manager.beans;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.annotation.Resource;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import bg.uni_sofia.conf_manager.enums.UserTypes;
import bg.uni_sofia.conf_manager.model.Admin;
import bg.uni_sofia.conf_manager.model.Employee;
import bg.uni_sofia.conf_manager.model.Lecturer;
import bg.uni_sofia.conf_manager.model.User;

/**
 * Session Bean implementation class Login
 */
@SessionScoped
@Named
@Path("/login")
public class LoginBean implements Serializable {
	@PersistenceContext
	private EntityManager em;
	private boolean isLogged;
	private UserTypes type;
	private long id;
	private String username;
	private String uuid;
	private Date creationDate;
	@Resource UserTransaction userTran;
	/**
	 * Default constructor.
	 */
	public LoginBean() {
	}
	 @POST
     @Consumes("application/json")
     @Produces("application/json")
     @Path("/mobileLogin")
     public Lecturer authenticateMobileUser(User user) {

             TypedQuery<Lecturer> lecturerQuery = em.createNamedQuery(
                             "getLecturerByName", Lecturer.class);
             lecturerQuery.setParameter("username", user.getUsername());
             List<Lecturer> realLecturer = lecturerQuery.getResultList();
             if (realLecturer != null && realLecturer.size() != 0) {
                     Lecturer lecturer = realLecturer.get(0);
                     try {
                             if (lecturer.isActive() && lecturer.getPassword().equals(hashPassword(user.getPassword()))) {
                                     isLogged = true;
                                     type = UserTypes.LECTURER;
                                     id = lecturer.getId();
                                     username = lecturer.getUsername();
                                     uuid = UUID.randomUUID().toString();
                                     creationDate = new Date();
                                     return lecturer;
                             }
                     } catch (NoSuchAlgorithmException e) {
                             e.printStackTrace();
                     }
             }

             return null;
     }
	@GET
	@Path("/logout")
	@Produces("application/json")
	public void logout() throws IllegalStateException, SecurityException, SystemException {
		
		if(type == UserTypes.LECTURER){
			TypedQuery<Lecturer> lecturerQuery = em.createNamedQuery(
					"getLecturerByName", Lecturer.class);
			lecturerQuery.setParameter("username", username);
			List<Lecturer> realLecturer = lecturerQuery.getResultList();
			Lecturer lecturer = realLecturer.get(0);
			lecturer.setLastLogin(creationDate);
			try {
				userTran.begin();
				em.merge(lecturer);
				userTran.commit();
			} catch (NotSupportedException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (SystemException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (IllegalStateException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (HeuristicMixedException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (HeuristicRollbackException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (RollbackException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			}
		}else if(type == UserTypes.EMPLOYEE){
			TypedQuery<Employee> employeeQuery = em.createNamedQuery(
					"getEmployeeByName", Employee.class);
			employeeQuery.setParameter("username", username);
			List<Employee> realEmployee = employeeQuery.getResultList();
			Employee employee = realEmployee.get(0);
			employee.setLastLogin(creationDate);		
			try {
				userTran.begin();
				em.merge(employee);
				userTran.commit();
			} catch (NotSupportedException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (SystemException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (IllegalStateException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (HeuristicMixedException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (HeuristicRollbackException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			} catch (RollbackException e) {
				// TODO Auto-generated catch block
				userTran.rollback();
			}
		}
		isLogged = false;
		type = null;
		id = 0;
		username = "";
		uuid = "";
		creationDate = null;
	}

	// @GET
	// @Path("/{id}")
	// @Produces("application/json")
	// public Student getStudentById(@PathParam("id") long id) {
	// TypedQuery<Student> query = em.createNamedQuery("getStudentById",
	// Student.class);
	// query.setParameter("id", id);
	// return query.getSingleResult();
	// }

	@POST
	@Consumes("application/json")
	public boolean authenticateUser(User newUser)
			throws NoSuchAlgorithmException, IllegalStateException, SecurityException, SystemException {
		TypedQuery<Lecturer> lecturerQuery = em.createNamedQuery(
				"getLecturerByName", Lecturer.class);
		lecturerQuery.setParameter("username", newUser.getUsername());

		TypedQuery<Admin> adminQuery = em.createNamedQuery("getAdminByName",
				Admin.class);
		adminQuery.setParameter("username", newUser.getUsername());
		TypedQuery<Employee> employeeQuery = em.createNamedQuery(
				"getEmployeeByName", Employee.class);
		employeeQuery.setParameter("username", newUser.getUsername());
		List<Lecturer> realLecturer = lecturerQuery.getResultList();
		List<Admin> realAdmin = adminQuery.getResultList();
		List<Employee> realEmployee = employeeQuery.getResultList();

		if (realLecturer != null && realLecturer.size() != 0) {
			if (realLecturer.get(0).getPassword()
					.equals(hashPassword(newUser.getPassword()))) {
				Lecturer lecturer = realLecturer.get(0);
				isLogged = true;
				type = UserTypes.LECTURER;
				id = lecturer.getId();
				username = lecturer.getUsername();
				uuid = UUID.randomUUID().toString();
				creationDate = new Date();
				return true;
			}
		} 
		if (realAdmin != null && realAdmin.size() != 0) {
			if (realAdmin.get(0).getPassword()
					.equals(hashPassword(newUser.getPassword()))) {
				isLogged = true;
				type = UserTypes.ADMIN;
				id = realAdmin.get(0).getId();
				username = realAdmin.get(0).getUsername();
				uuid = UUID.randomUUID().toString();
				creationDate = new Date();
				return true;
			}
		}
		if (realEmployee != null && realEmployee.size() != 0) {
			if (realEmployee.get(0).getPassword()
					.equals(hashPassword(newUser.getPassword()))) {
				Employee employee = realEmployee.get(0);
				isLogged = true;
				type = UserTypes.EMPLOYEE;
				id = employee.getId();
				username = employee.getUsername();
				uuid = UUID.randomUUID().toString();
				creationDate = new Date();
				return true;
			}
		}

		return false;

	}

	public String hashPassword(String password) throws NoSuchAlgorithmException {

		MessageDigest md = MessageDigest.getInstance("SHA-1");
		md.update(password.getBytes());
		byte byteData[] = md.digest();
		return new String(bytesToHex(byteData));

	}

	public static String bytesToHex(byte[] b) {
		char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		StringBuffer buf = new StringBuffer();
		for (int j = 0; j < b.length; j++) {
			buf.append(hexDigit[(b[j] >> 4) & 0x0f]);
			buf.append(hexDigit[b[j] & 0x0f]);
		}
		return buf.toString();
	}

	public boolean isLogged() {
		return isLogged;
	}

	public void setLogged(boolean isLogged) {
		this.isLogged = isLogged;
	}

	@GET
	@Path("/getType")
	@Produces("application/json")
	public String getActorsType() {
		return type.toString();
	}

	public UserTypes getType() {
		return type;
	}

	public void setType(UserTypes type) {
		this.type = type;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	@GET
	@Path("/getUsername")
	@Produces("application/json")
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getUuid() {
		return uuid;
	}

	public void setUuid(String uuid) {
		this.uuid = uuid;
	}

	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}
}
